`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: CBICR, Tsinghua Univ.
// Engineer: Hongyi Li
// 
// Create Date: 2024/12/23 11:58:54
// Design Name: 
// Module Name: Virtual Channel Allocation
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module VcAlloc
#(
    parameter DataWidth = 'd32,
    parameter FifoDepth = 'd4,
    parameter VCNumber  = 'd4
)(
    input                            clk, rst_n,
    input  [5*VCNumber   -1:0]       i_credit,
    input  [5*VCNumber*5 -1:0]       i_dir,
    output [5*VCNumber*5 -1:0]       o_next_vc,
    output [5*VCNumber   -1:0]       o_winner,
    output [             24:0]       o_adj_mat
);

wire  [VCNumber   -1 : 0]      i_valid_dir   [0:4];
wire  [VCNumber*5 -1 : 0]      next_vc_req   [0:4];
wire  [VCNumber*5 -1 : 0]      next_vc_grant [0:4];

wire  [VCNumber   -1 : 0]      contrib_adj   [0:4][0:4];
wire  [            4 : 0]      request_adj   [0:4];

assign o_next_vc = {next_vc_grant[4], next_vc_grant[3], next_vc_grant[2], next_vc_grant[1], next_vc_grant[0]};
assign o_adj_mat = {request_adj[4], request_adj[3], request_adj[2], request_adj[1], request_adj[0]};

genvar i, j, k;
generate
    /* -------------------------------- Send-Rtr View -----------------------------------------*/
    for (i = 0; i < 5; i = i + 1) begin // i: src_channel
        
        // Get i_valid_dir from i_dir
        for (j = 0; j < VCNumber; j = j + 1) begin // j: src_virtual_channel
            assign i_valid_dir[i][j] = |i_dir[i*(VCNumber*5)+j*5+4 : i*(VCNumber*5)+j*5];
            for (k = 0; k < 5; k = k + 1) begin // k: dst_router
                assign contrib_adj[k][i][j] = i_dir[i*(VCNumber*5)+j*5+k] & o_winner[i*VCNumber+j];
            end
        end

        // Merge to the shared Adj-Matrix
        for (k = 0; k < 5; k = k + 1) begin // k: dst_router
            assign request_adj[k][i] = | contrib_adj[k][i];
        end

        // Find Local Winnner (VC -[Arbitor]-> 1)
        RoundRobinArbitor #(
            .N(VCNumber)
        ) VCs_Arb_U (
            .clk(clk), .rst_n(rst_n),
            .i_req(i_valid_dir[i]), 
            .o_grant(o_winner[VCNumber*(i+1)-1 : VCNumber*i]) // ~ [ [VCNumber] [VCNumber] [VCNumber] ... ]
        );
    end

    /* -------------------------------- Recv-Rtr View -----------------------------------------*/
    for (k = 0; k < 5; k = k + 1) begin // i: dst_router (parallel)

        // Generate Requests
        for (j = 0; j < VCNumber; j = j + 1) begin // j: dst_virtual_channel
            for (i = 0; i < 5; i = i + 1) begin // k: src_router
                assign next_vc_req[k][5*j+i] = request_adj[k][i] & i_credit[5*j+i];
            end
        end

        // Allocator: k [5] -> j [VCNumber]
        SeparableAllocator #(
            .N(5), .M(VCNumber)
        ) Nxt_VCs_Alloc_U (
            .clk(clk), .rst_n(rst_n),
            .i_nm_req(next_vc_req[k]),
            .o_mn_grant(next_vc_grant[k])
        );
    end
endgenerate

endmodule